home *** CD-ROM | disk | FTP | other *** search
/ PD Collection CD 1 / PD Collection CD 1.iso / textual / pdftops / xpdf / c++ / Gfx < prev    next >
Text File  |  1996-06-09  |  43KB  |  1,639 lines

  1. //========================================================================
  2. //
  3. // Gfx.cc
  4. //
  5. // Copyright 1996 Derek B. Noonburg
  6. //
  7. //========================================================================
  8.  
  9. #ifdef __GNUC__
  10. //#pragma implementation
  11. #endif
  12.  
  13. #include <stdio.h>
  14. #include <stddef.h>
  15. #include <string.h>
  16. // snb94r@ecs.soton.ac.uk added stdarg for the table construction
  17. #include <stdarg.h>
  18. #include "gmem.h"
  19. #include "cover.h"
  20. #include "Object.h"
  21. #include "Array.h"
  22. #include "Dict.h"
  23. #include "Stream.h"
  24. #include "Lexer.h"
  25. #include "Parser.h"
  26. #include "GfxFont.h"
  27. #include "GfxState.h"
  28. #include "OutputDev.h"
  29. #include "PSOutput.h"
  30. #include "Flags.h"
  31. #include "Error.h"
  32. #include "Gfx.h"
  33.  
  34. //------------------------------------------------------------------------
  35. // Operator table
  36. //------------------------------------------------------------------------
  37.  
  38. // snb94r@ecs.soton.ac.uk removed this static table, since cfront refuses
  39. // to compile it, with a "initializer too long" error.  The table is instead
  40. // built dynamically with the new methods below.
  41.  
  42. #ifndef __riscos
  43. Operator Gfx::opTab[] = {
  44.   {"\"", 3, {tchkNum,    tchkNum,    tchkString},
  45.          &Gfx::opMoveSetShowText,    &Gfx::psMoveSetShowText},
  46.   {"'",  1, {tchkString},
  47.          &Gfx::opMoveShowText,       &Gfx::psMoveShowText},
  48.   {"B",  0, {tchkNone},
  49.          &Gfx::opFillStroke,         &Gfx::psFillStroke},
  50.   {"B*", 0, {tchkNone},
  51.          &Gfx::opEOFillStroke,       &Gfx::psEOFillStroke},
  52.   {"BI", 0, {tchkNone},
  53.          &Gfx::opBeginImage,         &Gfx::psBeginImage},
  54.   {"BT", 0, {tchkNone},
  55.          &Gfx::opBeginText,          &Gfx::psBeginText},
  56.   {"Do", 1, {tchkName},
  57.          &Gfx::opXObject,            &Gfx::psXObject},
  58.   {"EI", 0, {tchkNone},
  59.          &Gfx::opEndImage,           &Gfx::psEndImage},
  60.   {"ET", 0, {tchkNone},
  61.          &Gfx::opEndText,            &Gfx::psEndText},
  62.   {"F",  0, {tchkNone},
  63.          &Gfx::opFill,               &Gfx::psFill},
  64.   {"G",  1, {tchkNum},
  65.          &Gfx::opSetStrokeGray,      &Gfx::psSetStrokeGray},
  66.   {"ID", 0, {tchkNone},
  67.          &Gfx::opImageData,          &Gfx::psImageData},
  68.   {"J",  1, {tchkInt},
  69.          &Gfx::opSetLineCap,         &Gfx::psSetLineCap},
  70.   {"K",  4, {tchkNum,    tchkNum,    tchkNum,    tchkNum},
  71.          &Gfx::opSetStrokeCMYKColor, &Gfx::psSetStrokeCMYKColor},
  72.   {"M",  1, {tchkNum},
  73.          &Gfx::opSetMiterLimit,      &Gfx::psSetMiterLimit},
  74.   {"Q",  0, {tchkNone},
  75.          &Gfx::opRestore,            &Gfx::psRestore},
  76.   {"RG", 3, {tchkNum,    tchkNum,    tchkNum},
  77.          &Gfx::opSetStrokeRGBColor,  &Gfx::psSetStrokeRGBColor},
  78.   {"S",  0, {tchkNone},
  79.          &Gfx::opStroke,             &Gfx::psStroke},
  80.   {"T*", 0, {tchkNone},
  81.          &Gfx::opTextNextLine,       &Gfx::psTextNextLine},
  82.   {"TD", 2, {tchkNum,    tchkNum},
  83.          &Gfx::opTextMoveSet,        &Gfx::psTextMoveSet},
  84.   {"TJ", 1, {tchkArray},
  85.          &Gfx::opShowSpaceText,      &Gfx::psShowSpaceText},
  86.   {"TL", 1, {tchkNum},
  87.          &Gfx::opSetTextLeading,     &Gfx::psSetTextLeading},
  88.   {"Tc", 1, {tchkNum},
  89.          &Gfx::opSetCharSpacing,     &Gfx::psSetCharSpacing},
  90.   {"Td", 2, {tchkNum,    tchkNum},
  91.          &Gfx::opTextMove,           &Gfx::psTextMove},
  92.   {"Tf", 2, {tchkName,   tchkNum},
  93.          &Gfx::opSetFont,            &Gfx::psSetFont},
  94.   {"Tj", 1, {tchkString},
  95.          &Gfx::opShowText,           &Gfx::psShowText},
  96.   {"Tm", 6, {tchkNum,    tchkNum,    tchkNum,    tchkNum,
  97.          tchkNum,    tchkNum},
  98.          &Gfx::opSetTextMatrix,      &Gfx::psSetTextMatrix},
  99.   {"Tr", 1, {tchkInt},
  100.          &Gfx::opSetTextRender,      &Gfx::psSetTextRender},
  101.   {"Ts", 1, {tchkNum},
  102.          &Gfx::opSetTextRise,        &Gfx::psSetTextRise},
  103.   {"Tw", 1, {tchkNum},
  104.          &Gfx::opSetWordSpacing,     &Gfx::psSetWordSpacing},
  105.   {"Tz", 1, {tchkNum},
  106.          &Gfx::opSetHorizScaling,    &Gfx::psSetHorizScaling},
  107.   {"W",  0, {tchkNone},
  108.          &Gfx::opClip,               &Gfx::psClip},
  109.   {"W*", 0, {tchkNone},
  110.          &Gfx::opEOClip,             &Gfx::psEOClip},
  111.   {"b",  0, {tchkNone},
  112.          &Gfx::opCloseFillStroke,    &Gfx::psCloseFillStroke},
  113.   {"b*", 0, {tchkNone},
  114.          &Gfx::opCloseEOFillStroke,  &Gfx::psCloseEOFillStroke},
  115.   {"c",  6, {tchkNum,    tchkNum,    tchkNum,    tchkNum,
  116.          tchkNum,    tchkNum},
  117.          &Gfx::opCurveTo,            &Gfx::psCurveTo},
  118.   {"cm", 6, {tchkNum,    tchkNum,    tchkNum,    tchkNum,
  119.          tchkNum,    tchkNum},
  120.          &Gfx::opConcat,             &Gfx::psConcat},
  121.   {"d",  2, {tchkArray,  tchkNum},
  122.          &Gfx::opSetDash,            &Gfx::psSetDash},
  123.   {"d0", 2, {tchkNum,    tchkNum},
  124.          &Gfx::opSetCharWidth,       &Gfx::psSetCharWidth},
  125.   {"d1", 2, {tchkNum,    tchkNum,    tchkNum,    tchkNum,
  126.          tchkNum,    tchkNum},
  127.          &Gfx::opSetCacheDevice,     &Gfx::psSetCacheDevice},
  128.   {"f",  0, {tchkNone},
  129.          &Gfx::opFill,               &Gfx::psFill},
  130.   {"f*", 0, {tchkNone},
  131.          &Gfx::opEOFill,             &Gfx::psEOFill},
  132.   {"g",  1, {tchkNum},
  133.          &Gfx::opSetFillGray,        &Gfx::psSetFillGray},
  134.   {"h",  0, {tchkNone},
  135.          &Gfx::opClosePath,          &Gfx::psClosePath},
  136.   {"i",  1, {tchkNum},
  137.          &Gfx::opSetFlat,            &Gfx::psSetFlat},
  138.   {"j",  1, {tchkInt},
  139.          &Gfx::opSetLineJoin,        &Gfx::psSetLineJoin},
  140.   {"k",  4, {tchkNum,    tchkNum,    tchkNum,    tchkNum},
  141.          &Gfx::opSetFillCMYKColor,   &Gfx::psSetFillCMYKColor},
  142.   {"l",  2, {tchkNum,    tchkNum},
  143.          &Gfx::opLineTo,             &Gfx::psLineTo},
  144.   {"m",  2, {tchkNum,    tchkNum},
  145.          &Gfx::opMoveTo,             &Gfx::psMoveTo},
  146.   {"n",  0, {tchkNone},
  147.          &Gfx::opEndPath,            &Gfx::psEndPath},
  148.   {"q",  0, {tchkNone},
  149.          &Gfx::opSave,               &Gfx::psSave},
  150.   {"re", 4, {tchkNum,    tchkNum,    tchkNum,    tchkNum},
  151.          &Gfx::opRectangle,          &Gfx::psRectangle},
  152.   {"rg", 3, {tchkNum,    tchkNum,    tchkNum},
  153.          &Gfx::opSetFillRGBColor,    &Gfx::psSetFillRGBColor},
  154.   {"s",  0, {tchkNone},
  155.          &Gfx::opCloseStroke,        &Gfx::psCloseStroke},
  156.   {"v",  4, {tchkNum,    tchkNum,    tchkNum,    tchkNum},
  157.          &Gfx::opCurveTo1,           &Gfx::psCurveTo1},
  158.   {"w",  1, {tchkNum},
  159.          &Gfx::opSetLineWidth,       &Gfx::psSetLineWidth},
  160.   {"y",  4, {tchkNum,    tchkNum,    tchkNum,    tchkNum},
  161.          &Gfx::opCurveTo2,           &Gfx::psCurveTo2}
  162.  
  163. };
  164.  
  165. #define numOps (sizeof(opTab) / sizeof(Operator))
  166. #endif
  167.  
  168. #ifdef __riscos
  169. // snb94r@ecs.soton.ac.uk added this - this is ugly, and add_Gfx_op should abort()
  170. // if the size is exceeded./
  171. #define numOps 58
  172. Operator* Gfx::opTab = 0;
  173.  
  174. #include "GfxTable.h"
  175.  
  176. void Gfx::add_Gfx_op(const char *name, int argc,
  177.     void (Gfx::*f1)(Object []), void (Gfx::*f2)(Object []), ...)
  178. {
  179.     static int addctr = 0;
  180.     va_list ap;
  181.     
  182.         /* bitwise copy is OK */
  183.         strcpy(opTab[addctr].name, name);
  184.     opTab[addctr].numArgs = argc;
  185.     opTab[addctr].func = f1;
  186.     opTab[addctr].psFunc = f2;
  187.     
  188.     if (!argc) argc = 1;
  189.     
  190.     va_start(ap, f2);
  191.     // jump out to C because cfront rejects va_arg
  192.     enter_Gfx_ops((int *)(opTab[addctr].tchk), argc, ap);
  193.     va_end(ap);
  194.     
  195.     if (++addctr >= numOps) {
  196.             --addctr;
  197.     }
  198. }
  199.  
  200. void Gfx::init_opTab()
  201. // new function by snb to initialise the table
  202. {
  203.         static int done = 0;
  204.         if (done++) return;
  205.         
  206.         opTab = new Operator[numOps];
  207.  
  208.   /* autogenerated by:  gawk -f awks.script cmdtable > sourcecode */
  209.   add_Gfx_op("\"",3,&Gfx::opMoveSetShowText,&Gfx::psMoveSetShowText,tchkNum,tchkNum,tchkString);
  210.   add_Gfx_op("'",1,&Gfx::opMoveShowText,&Gfx::psMoveShowText,tchkString);
  211.   add_Gfx_op("B",0,&Gfx::opFillStroke,&Gfx::psFillStroke,tchkNone);
  212.   add_Gfx_op("B*",0,&Gfx::opEOFillStroke,&Gfx::psEOFillStroke,tchkNone);
  213.   add_Gfx_op("BI",0,&Gfx::opBeginImage,&Gfx::psBeginImage,tchkNone);
  214.   add_Gfx_op("BT",0,&Gfx::opBeginText,&Gfx::psBeginText,tchkNone);
  215.   add_Gfx_op("Do",1,&Gfx::opXObject,&Gfx::psXObject,tchkName);
  216.   add_Gfx_op("EI",0,&Gfx::opEndImage,&Gfx::psEndImage,tchkNone);
  217.   add_Gfx_op("ET",0,&Gfx::opEndText,&Gfx::psEndText,tchkNone);
  218.   add_Gfx_op("F",0,&Gfx::opFill,&Gfx::psFill,tchkNone);
  219.   add_Gfx_op("G",1,&Gfx::opSetStrokeGray,&Gfx::psSetStrokeGray,tchkNum);
  220.   add_Gfx_op("ID",0,&Gfx::opImageData,&Gfx::psImageData,tchkNone);
  221.   add_Gfx_op("J",1,&Gfx::opSetLineCap,&Gfx::psSetLineCap,tchkInt);
  222.   add_Gfx_op("K",4,&Gfx::opSetStrokeCMYKColor,&Gfx::psSetStrokeCMYKColor,tchkNum,tchkNum,tchkNum,tchkNum);
  223.   add_Gfx_op("M",1,&Gfx::opSetMiterLimit,&Gfx::psSetMiterLimit,tchkNum);
  224.   add_Gfx_op("Q",0,&Gfx::opRestore,&Gfx::psRestore,tchkNone);
  225.   add_Gfx_op("RG",3,&Gfx::opSetStrokeRGBColor,&Gfx::psSetStrokeRGBColor,tchkNum,tchkNum,tchkNum);
  226.   add_Gfx_op("S",0,&Gfx::opStroke,&Gfx::psStroke,tchkNone);
  227.   add_Gfx_op("T*",0,&Gfx::opTextNextLine,&Gfx::psTextNextLine,tchkNone);
  228.   add_Gfx_op("TD",2,&Gfx::opTextMoveSet,&Gfx::psTextMoveSet,tchkNum,tchkNum);
  229.   add_Gfx_op("TJ",1,&Gfx::opShowSpaceText,&Gfx::psShowSpaceText,tchkArray);
  230.   add_Gfx_op("TL",1,&Gfx::opSetTextLeading,&Gfx::psSetTextLeading,tchkNum);
  231.   add_Gfx_op("Tc",1,&Gfx::opSetCharSpacing,&Gfx::psSetCharSpacing,tchkNum);
  232.   add_Gfx_op("Td",2,&Gfx::opTextMove,&Gfx::psTextMove,tchkNum,tchkNum);
  233.   add_Gfx_op("Tf",2,&Gfx::opSetFont,&Gfx::psSetFont,tchkName,tchkNum);
  234.   add_Gfx_op("Tj",1,&Gfx::opShowText,&Gfx::psShowText,tchkString);
  235.   add_Gfx_op("Tm",6,&Gfx::opSetTextMatrix,&Gfx::psSetTextMatrix,tchkNum,tchkNum,tchkNum,tchkNum,tchkNum,tchkNum);
  236.   add_Gfx_op("Tr",1,&Gfx::opSetTextRender,&Gfx::psSetTextRender,tchkInt);
  237.   add_Gfx_op("Ts",1,&Gfx::opSetTextRise,&Gfx::psSetTextRise,tchkNum);
  238.   add_Gfx_op("Tw",1,&Gfx::opSetWordSpacing,&Gfx::psSetWordSpacing,tchkNum);
  239.   add_Gfx_op("Tz",1,&Gfx::opSetHorizScaling,&Gfx::psSetHorizScaling,tchkNum);
  240.   add_Gfx_op("W",0,&Gfx::opClip,&Gfx::psClip,tchkNone);
  241.   add_Gfx_op("W*",0,&Gfx::opEOClip,&Gfx::psEOClip,tchkNone);
  242.   add_Gfx_op("b",0,&Gfx::opCloseFillStroke,&Gfx::psCloseFillStroke,tchkNone);
  243.   add_Gfx_op("b*",0,&Gfx::opCloseEOFillStroke,&Gfx::psCloseEOFillStroke,tchkNone);
  244.   add_Gfx_op("c",6,&Gfx::opCurveTo,&Gfx::psCurveTo,tchkNum,tchkNum,tchkNum,tchkNum,tchkNum,tchkNum);
  245.   add_Gfx_op("cm",6,&Gfx::opConcat,&Gfx::psConcat,tchkNum,tchkNum,tchkNum,tchkNum,tchkNum,tchkNum);
  246.   add_Gfx_op("d",2,&Gfx::opSetDash,&Gfx::psSetDash,tchkArray,tchkNum);
  247.   add_Gfx_op("d0",2,&Gfx::opSetCharWidth,&Gfx::psSetCharWidth,tchkNum,tchkNum);
  248.   add_Gfx_op("d1",2,&Gfx::opSetCacheDevice,&Gfx::psSetCacheDevice,tchkNum,tchkNum);
  249.   add_Gfx_op("f",0,&Gfx::opFill,&Gfx::psFill,tchkNone);
  250.   add_Gfx_op("f*",0,&Gfx::opEOFill,&Gfx::psEOFill,tchkNone);
  251.   add_Gfx_op("g",1,&Gfx::opSetFillGray,&Gfx::psSetFillGray,tchkNum);
  252.   add_Gfx_op("h",0,&Gfx::opClosePath,&Gfx::psClosePath,tchkNone);
  253.   add_Gfx_op("i",1,&Gfx::opSetFlat,&Gfx::psSetFlat,tchkNum);
  254.   add_Gfx_op("j",1,&Gfx::opSetLineJoin,&Gfx::psSetLineJoin,tchkInt);
  255.   add_Gfx_op("k",4,&Gfx::opSetFillCMYKColor,&Gfx::psSetFillCMYKColor,tchkNum,tchkNum,tchkNum,tchkNum);
  256.   add_Gfx_op("l",2,&Gfx::opLineTo,&Gfx::psLineTo,tchkNum,tchkNum);
  257.   add_Gfx_op("m",2,&Gfx::opMoveTo,&Gfx::psMoveTo,tchkNum,tchkNum);
  258.   add_Gfx_op("n",0,&Gfx::opEndPath,&Gfx::psEndPath,tchkNone);
  259.   add_Gfx_op("q",0,&Gfx::opSave,&Gfx::psSave,tchkNone);
  260.   add_Gfx_op("re",4,&Gfx::opRectangle,&Gfx::psRectangle,tchkNum,tchkNum,tchkNum,tchkNum);
  261.   add_Gfx_op("rg",3,&Gfx::opSetFillRGBColor,&Gfx::psSetFillRGBColor,tchkNum,tchkNum,tchkNum);
  262.   add_Gfx_op("s",0,&Gfx::opCloseStroke,&Gfx::psCloseStroke,tchkNone);
  263.   add_Gfx_op("v",4,&Gfx::opCurveTo1,&Gfx::psCurveTo1,tchkNum,tchkNum,tchkNum,tchkNum);
  264.   add_Gfx_op("w",1,&Gfx::opSetLineWidth,&Gfx::psSetLineWidth,tchkNum);
  265.   add_Gfx_op("y",4,&Gfx::opCurveTo2,&Gfx::psCurveTo2,tchkNum,tchkNum,tchkNum,tchkNum);
  266.  
  267. }
  268. // end of insertion by snb94r@ecs.soton.ac.uk
  269. #endif
  270.  
  271. //------------------------------------------------------------------------
  272. // Gfx
  273. //------------------------------------------------------------------------
  274.  
  275. Gfx::Gfx(OutputDev *out1, Dict *fontDict, Dict *xObjDict1,
  276.      int dpi, int x1, int y1, int x2, int y2, int rotate) {
  277. #ifndef __riscos
  278. // snb94r@ecs.soton.ac.uk added this to construct the operator table
  279.   init_opTab();
  280. #endif
  281.   out = out1;
  282.   psOut = NULL;
  283.   if (fontDict)
  284.     fonts = new GfxFontDict(fontDict);
  285.   else
  286.     fonts = NULL;
  287.   xObjDict = xObjDict1;
  288.   state = new GfxState(dpi, x1, y1, x2, y2, rotate, out->upsideDown());
  289.   fontChanged = gFalse;
  290.   clip = clipNone;
  291.   psFont = NULL;
  292.   psFontSize = 1;
  293.   psGfxFont = NULL;
  294.   out->updateAll(state);
  295.   out->setPageSize(state->getPageWidth(), state->getPageHeight());
  296.   out->setCTM(state->getCTM());
  297.   out->clear();
  298. }
  299.  
  300. Gfx::Gfx(PSOutput *psOut1, Dict *fontDict, Dict *xObjDict1,
  301.      int dpi, int x1, int y1, int x2, int y2, int rotate) {
  302. #ifndef __riscos
  303. // snb94r@ecs.soton.ac.uk added this to construct the operator table
  304.   init_opTab();
  305. #endif
  306.   psOut = psOut1;
  307.   out = NULL;
  308.   //~ the fonts are needed to adjust for imperfect match with PS fonts
  309.   if (fontDict)
  310.     fonts = new GfxFontDict(fontDict);
  311.   else
  312.     fonts = NULL;
  313.   xObjDict = xObjDict1;
  314.   state = NULL;
  315.   fontChanged = gFalse;
  316.   clip = clipNone;
  317.   psFont = NULL;
  318.   psFontSize = 1;
  319.   psGfxFont = NULL;
  320. }
  321.  
  322. Gfx::~Gfx() {
  323.   if (fonts)
  324.     delete fonts;
  325.   if (state)
  326.     delete state;
  327.   if (psFont)
  328.     delete psFont;
  329. }
  330.  
  331. void Gfx::display(Array *a1) {
  332.   cover("Gfx::display(Array)");
  333.   parser = NULL;
  334.   a = a1;
  335.   index = 0;
  336.   go();
  337. }
  338.  
  339. void Gfx::display(Stream *str1) {
  340.   cover("Gfx::display(Stream)");
  341.   parser = new Parser(new Lexer(str1, gFalse));
  342.   a = NULL;
  343.   go();
  344. }
  345.  
  346. void Gfx::go() {
  347.   Object obj;
  348.   Object args[maxArgs];
  349.   int i, j;
  350.  
  351.   i = 0;
  352.   nextObj(&obj);
  353.   while (!obj.isEOF()) {
  354.     if (obj.isCmd()) {
  355.       if (printCommands) {
  356.     obj.print(stdout);
  357.     for (j = 0; j < i; ++j) {
  358.       printf(" ");
  359.       args[j].print(stdout);
  360.     }
  361.     printf("\n");
  362.       }
  363.       execOp(&obj, args, i);
  364.       obj.free();
  365.       for (j = 0; j < i; ++j)
  366.     args[j].free();
  367.       i = 0;
  368.     } else if (i < maxArgs) {
  369.       args[i++] = obj;
  370.     } else {
  371.       error(0, "Too many args in content stream");
  372.       if (printCommands) {
  373.     printf("throwing away arg: ");
  374.     obj.print(stdout);
  375.     printf("\n");
  376.       }
  377.       obj.free();
  378.     }
  379.     nextObj(&obj);
  380.   }
  381.   obj.free();
  382.   if (i > 0) {
  383.     error(0, "Leftover args in content stream");
  384.     for (j = 0; j < i; ++j)
  385.       args[j].free();
  386.   }
  387.   done();
  388.   if (out)
  389.     out->dump();
  390.   if (printCommands)
  391.     fflush(stdout);
  392. }
  393.  
  394. void Gfx::execOp(Object *cmd, Object args[], int numArgs) {
  395.   Operator *op;
  396.   char *name;
  397.   int i;
  398.  
  399.   // find operator
  400.   name = cmd->getName();
  401.   if (!(op = findOp(name))) {
  402.     error(0, "Unknown operator '%s'", name);
  403.     return;
  404.   }
  405.  
  406.   // type check args
  407.   if (numArgs != op->numArgs) {
  408.     error(0, "Wrong number (%d) of args to '%s' operator", numArgs, name);
  409.     return;
  410.   }
  411.   for (i = 0; i < numArgs; ++i) {
  412.     if (!checkArg(&args[i], op->tchk[i])) {
  413.       error(0, "Arg #%d to '%s' operator is wrong type (%s)",
  414.         i, name, args[i].getTypeName());
  415.       return;
  416.     }
  417.   }
  418.  
  419.   // do it
  420.   if (out)
  421.     (this->*op->func)(args);
  422.   else
  423.     (this->*op->psFunc)(args);
  424. }
  425.  
  426. Operator *Gfx::findOp(char *name) {
  427.   int a, b, m, cmp;
  428.  
  429.   a = -1;
  430.   b = numOps;
  431.   // invariant: opTab[a] < name < opTab[b]
  432.   while (b - a > 1) {
  433.     m = (a + b) / 2;
  434.     cmp = strcmp(opTab[m].name, name);
  435.     if (cmp < 0)
  436.       a = m;
  437.     else if (cmp > 0)
  438.       b = m;
  439.     else
  440.       a = b = m;
  441.   }
  442.   if (cmp != 0)
  443.     return NULL;
  444.   return &opTab[a];
  445. }
  446.  
  447. GBool Gfx::checkArg(Object *arg, TchkType type) {
  448.   switch (type) {
  449.   case tchkBool:   return arg->isBool();
  450.   case tchkInt:    return arg->isInt();
  451.   case tchkNum:    return arg->isNum();
  452.   case tchkString: return arg->isString();
  453.   case tchkName:   return arg->isName();
  454.   case tchkArray:  return arg->isArray();
  455.   case tchkNone:   return gFalse;
  456.   }
  457.   return gFalse;
  458. }
  459.  
  460. Object *Gfx::nextObj(Object *obj) {
  461.   if (a) {
  462.     if (index < a->getLength())
  463.       a->get(index++, obj);
  464.     else
  465.       obj->initEOF();
  466.   } else {
  467.     parser->getObj(obj);
  468.   }
  469.   return obj;
  470. }
  471.  
  472. void Gfx::done() {
  473.   if (parser)
  474.     delete parser;
  475. }
  476.  
  477. //------------------------------------------------------------------------
  478. // graphics state operators
  479. //------------------------------------------------------------------------
  480.  
  481. void Gfx::opSave(Object args[]) {
  482.   cover("Gfx::opSave");
  483.   out->saveState(state);
  484.   state = state->save();
  485. }
  486.  
  487. void Gfx::psSave(Object args[]) {
  488.   psOut->writePS("q\n");
  489. }
  490.  
  491. void Gfx::opRestore(Object args[]) {
  492.   cover("Gfx::opRestore");
  493.   state = state->restore();
  494.   out->restoreState(state);
  495. }
  496.  
  497. void Gfx::psRestore(Object args[]) {
  498.   psOut->writePS("Q\n");
  499. }
  500.  
  501. void Gfx::opConcat(Object args[]) {
  502.   cover("Gfx::opConcat");
  503.   state->concatCTM(args[0].getNum(), args[1].getNum(),
  504.            args[2].getNum(), args[3].getNum(),
  505.            args[4].getNum(), args[5].getNum());
  506.   out->updateCTM(state);
  507.   fontChanged = gTrue;
  508. }
  509.  
  510. void Gfx::psConcat(Object args[]) {
  511.   psOut->writePS("[%g %g %g %g %g %g] cm\n",
  512.          args[0].getNum(), args[1].getNum(),
  513.          args[2].getNum(), args[3].getNum(),
  514.          args[4].getNum(), args[5].getNum());
  515. }
  516.  
  517. void Gfx::opSetDash(Object args[]) {
  518.   Array *a;
  519.   int length;
  520.   Object obj;
  521.   double *dash;
  522.   int i;
  523.  
  524.   cover("Gfx::opSetDash");
  525.   a = args[0].getArray();
  526.   length = a->getLength();
  527.   if (length == 0) {
  528.     dash = NULL;
  529.   } else {
  530.     dash = (double *)gmalloc(length * sizeof(double));
  531.     for (i = 0; i < length; ++i) {
  532.       dash[i] = a->get(i, &obj)->getNum();
  533.       obj.free();
  534.     }
  535.   }
  536.   state->setLineDash(dash, length, args[1].getNum());
  537.   out->updateLineDash(state);
  538. }
  539.  
  540. void Gfx::psSetDash(Object args[]) {
  541.   Array *a;
  542.   int length;
  543.   Object obj;
  544.   int i;
  545.  
  546.   a = args[0].getArray();
  547.   length = a->getLength();
  548.   psOut->writePS("[");
  549.   for (i = 0; i < length; ++i) {
  550.     psOut->writePS("%g%s", a->get(i, &obj)->getNum(),
  551.            (i == length-1) ? "" : " ");
  552.     obj.free();
  553.   }
  554.   psOut->writePS("] %g d\n", args[1].getNum());
  555. }
  556.  
  557. void Gfx::opSetFlat(Object args[]) {
  558.   cover("Gfx::opSetFlat");
  559.   state->setFlatness((int)args[0].getNum());
  560.   out->updateFlatness(state);
  561. }
  562.  
  563. void Gfx::psSetFlat(Object args[]) {
  564.   psOut->writePS("%g i\n", args[0].getNum());
  565. }
  566.  
  567. void Gfx::opSetLineJoin(Object args[]) {
  568.   cover("Gfx::opSetLineJoin");
  569.   state->setLineJoin(args[0].getInt());
  570.   out->updateLineJoin(state);
  571. }
  572.  
  573. void Gfx::psSetLineJoin(Object args[]) {
  574.   psOut->writePS("%d j\n", args[0].getInt());
  575. }
  576.  
  577. void Gfx::opSetLineCap(Object args[]) {
  578.   cover("Gfx::opSetLineCap");
  579.   state->setLineCap(args[0].getInt());
  580.   out->updateLineCap(state);
  581. }
  582.  
  583. void Gfx::psSetLineCap(Object args[]) {
  584.   psOut->writePS("%d J\n", args[0].getInt());
  585. }
  586.  
  587. void Gfx::opSetMiterLimit(Object args[]) {
  588.   cover("Gfx::opSetMiterLimit");
  589.   state->setMiterLimit(args[0].getNum());
  590.   out->updateMiterLimit(state);
  591. }
  592.  
  593. void Gfx::psSetMiterLimit(Object args[]) {
  594.   psOut->writePS("%g M\n", args[0].getNum());
  595. }
  596.  
  597. void Gfx::opSetLineWidth(Object args[]) {
  598.   cover("Gfx::opSetLineWidth");
  599.   state->setLineWidth(args[0].getNum());
  600.   out->updateLineWidth(state);
  601. }
  602.  
  603. void Gfx::psSetLineWidth(Object args[]) {
  604.   psOut->writePS("%g w\n", args[0].getNum());
  605. }
  606.  
  607. //------------------------------------------------------------------------
  608. // color operators
  609. //------------------------------------------------------------------------
  610.  
  611. void Gfx::opSetFillGray(Object args[]) {
  612.   cover("Gfx::opSetFillGray");
  613.   state->setFillGray(args[0].getNum());
  614.   out->updateFillColor(state);
  615. }
  616.  
  617. void Gfx::psSetFillGray(Object args[]) {
  618.   psOut->writePS("%g g\n", args[0].getNum());
  619. }
  620.  
  621. void Gfx::opSetStrokeGray(Object args[]) {
  622.   cover("Gfx::opSetStrokeGray");
  623.   state->setStrokeGray(args[0].getNum());
  624.   out->updateStrokeColor(state);
  625. }
  626.  
  627. void Gfx::psSetStrokeGray(Object args[]) {
  628.   psOut->writePS("%g G\n", args[0].getNum());
  629. }
  630.  
  631. void Gfx::opSetFillCMYKColor(Object args[]) {
  632.   cover("Gfx::opSetFillCMYKColor");
  633.   state->setFillCMYK(args[0].getNum(), args[1].getNum(),
  634.              args[2].getNum(), args[3].getNum());
  635.   out->updateFillColor(state);
  636. }
  637.  
  638. void Gfx::psSetFillCMYKColor(Object args[]) {
  639.   psOut->writePS("%g %g %g %g k\n",
  640.          args[0].getNum(), args[1].getNum(),
  641.          args[2].getNum(), args[3].getNum());
  642. }
  643.  
  644. void Gfx::opSetStrokeCMYKColor(Object args[]) {
  645.   cover("Gfx::opSetStrokeCMYKColor");
  646.   state->setStrokeCMYK(args[0].getNum(), args[1].getNum(),
  647.                args[2].getNum(), args[3].getNum());
  648.   out->updateStrokeColor(state);
  649. }
  650.  
  651. void Gfx::psSetStrokeCMYKColor(Object args[]) {
  652.   psOut->writePS("%g %g %g %g K\n",
  653.          args[0].getNum(), args[1].getNum(),
  654.          args[2].getNum(), args[3].getNum());
  655. }
  656.  
  657. void Gfx::opSetFillRGBColor(Object args[]) {
  658.   cover("Gfx::opSetFillRGBColor");
  659.   state->setFillRGB(args[0].getNum(), args[1].getNum(), args[2].getNum());
  660.   out->updateFillColor(state);
  661. }
  662.  
  663. void Gfx::psSetFillRGBColor(Object args[]) {
  664.   psOut->writePS("%g %g %g rg\n",
  665.          args[0].getNum(), args[1].getNum(), args[2].getNum());
  666. }
  667.  
  668. void Gfx::opSetStrokeRGBColor(Object args[]) {
  669.   cover("Gfx::opSetStrokeRGBColor");
  670.   state->setStrokeRGB(args[0].getNum(), args[1].getNum(), args[2].getNum());
  671.   out->updateStrokeColor(state);
  672. }
  673.  
  674. void Gfx::psSetStrokeRGBColor(Object args[]) {
  675.   psOut->writePS("%g %g %g RG\n",
  676.          args[0].getNum(), args[1].getNum(), args[2].getNum());
  677. }
  678.  
  679. //------------------------------------------------------------------------
  680. // path segment operators
  681. //------------------------------------------------------------------------
  682.  
  683. void Gfx::opMoveTo(Object args[]) {
  684.   cover("Gfx::opMoveTo");
  685.   state->moveTo(args[0].getNum(), args[1].getNum());
  686. }
  687.  
  688. void Gfx::psMoveTo(Object args[]) {
  689.   psOut->writePS("%g %g m\n", args[0].getNum(), args[1].getNum());
  690. }
  691.  
  692. void Gfx::opLineTo(Object args[]) {
  693.   cover("Gfx::opLineTo");
  694.   if (!state->isPath()) {
  695.     error(0, "No current point in lineto");
  696.     return;
  697.   }
  698.   state->lineTo(args[0].getNum(), args[1].getNum());
  699. }
  700.  
  701. void Gfx::psLineTo(Object args[]) {
  702.   psOut->writePS("%g %g l\n", args[0].getNum(), args[1].getNum());
  703. }
  704.  
  705. void Gfx::opCurveTo(Object args[]) {
  706.   double x1, y1, x2, y2, x3, y3;
  707.  
  708.   cover("Gfx::opCurveTo");
  709.   if (!state->isPath()) {
  710.     error(0, "No current point in curveto");
  711.     return;
  712.   }
  713.   x1 = args[0].getNum();
  714.   y1 = args[1].getNum();
  715.   x2 = args[2].getNum();
  716.   y2 = args[3].getNum();
  717.   x3 = args[4].getNum();
  718.   y3 = args[5].getNum();
  719.   state->curveTo(x1, y1, x2, y2, x3, y3);
  720. }
  721.  
  722. void Gfx::psCurveTo(Object args[]) {
  723.   psOut->writePS("%g %g %g %g %g %g c\n",
  724.          args[0].getNum(), args[1].getNum(), args[2].getNum(),
  725.          args[3].getNum(), args[4].getNum(), args[5].getNum());
  726. }
  727.  
  728. void Gfx::opCurveTo1(Object args[]) {
  729.   double x1, y1, x2, y2, x3, y3;
  730.  
  731.   cover("Gfx::opCurveTo1");
  732.   if (!state->isPath()) {
  733.     error(0, "No current point in curveto1");
  734.     return;
  735.   }
  736.   x1 = state->getCurX();
  737.   y1 = state->getCurY();
  738.   x2 = args[0].getNum();
  739.   y2 = args[1].getNum();
  740.   x3 = args[2].getNum();
  741.   y3 = args[3].getNum();
  742.   state->curveTo(x1, y1, x2, y2, x3, y3);
  743. }
  744.  
  745. void Gfx::psCurveTo1(Object args[]) {
  746.   psOut->writePS("%g %g %g %g v\n",
  747.          args[0].getNum(), args[1].getNum(),
  748.          args[2].getNum(), args[3].getNum());
  749. }
  750.  
  751. void Gfx::opCurveTo2(Object args[]) {
  752.   double x1, y1, x2, y2, x3, y3;
  753.  
  754.   cover("Gfx::opCurveTo2");
  755.   if (!state->isPath()) {
  756.     error(0, "No current point in curveto2");
  757.     return;
  758.   }
  759.   x1 = args[0].getNum();
  760.   y1 = args[1].getNum();
  761.   x2 = args[2].getNum();
  762.   y2 = args[3].getNum();
  763.   x3 = x2;
  764.   y3 = y2;
  765.   state->curveTo(x1, y1, x2, y2, x3, y3);
  766. }
  767.  
  768. void Gfx::psCurveTo2(Object args[]) {
  769.   psOut->writePS("%g %g %g %g y\n",
  770.          args[0].getNum(), args[1].getNum(),
  771.          args[2].getNum(), args[3].getNum());
  772. }
  773.  
  774. void Gfx::opRectangle(Object args[]) {
  775.   double x, y, w, h;
  776.  
  777.   cover("Gfx::opRectangle");
  778.   x = args[0].getNum();
  779.   y = args[1].getNum();
  780.   w = args[2].getNum();
  781.   h = args[3].getNum();
  782.   state->moveTo(x, y);
  783.   state->lineTo(x + w, y);
  784.   state->lineTo(x + w, y + h);
  785.   state->lineTo(x, y + h);
  786.   state->closePath();
  787. }
  788.  
  789. void Gfx::psRectangle(Object args[]) {
  790.   psOut->writePS("%g %g %g %g re\n",
  791.          args[0].getNum(), args[1].getNum(),
  792.          args[2].getNum(), args[3].getNum());
  793. }
  794.  
  795. void Gfx::opClosePath(Object args[]) {
  796.   GfxPath *path;
  797.  
  798.   cover("Gfx::opClosePath");
  799.   if (!state->isPath()) {
  800.     error(0, "No current point in closepath");
  801.     return;
  802.   }
  803.   state->closePath();
  804.   path = state->getPath();
  805. }
  806.  
  807. void Gfx::psClosePath(Object args[]) {
  808.   psOut->writePS("h\n");
  809. }
  810.  
  811. //------------------------------------------------------------------------
  812. // path painting operators
  813. //------------------------------------------------------------------------
  814.  
  815. void Gfx::opEndPath(Object args[]) {
  816.   cover("Gfx::opEndPath");
  817.   doEndPath();
  818. }
  819.  
  820. void Gfx::psEndPath(Object args[]) {
  821.   if (clip != clipNone)
  822.     psDoClip(gFalse);
  823.   psOut->writePS("n\n");
  824. }
  825.  
  826. void Gfx::opStroke(Object args[]) {
  827.   cover("Gfx::opStroke");
  828.   if (!state->isPath()) {
  829.     error(0, "No path in stroke");
  830.     return;
  831.   }
  832.   out->stroke(state);
  833.   doEndPath();
  834. }
  835.  
  836. void Gfx::psStroke(Object args[]) {
  837.   if (clip != clipNone)
  838.     psOut->writePS("gsave\n");
  839.   psOut->writePS("S\n");
  840.   if (clip != clipNone)
  841.     psDoClip(gTrue);
  842. }
  843.  
  844. void Gfx::opCloseStroke(Object args[]) {
  845.   cover("Gfx::opCloseStroke");
  846.   if (!state->isPath()) {
  847.     error(0, "No path in closepath/stroke");
  848.     return;
  849.   }
  850.   state->closePath();
  851.   out->stroke(state);
  852.   doEndPath();
  853. }
  854.  
  855. void Gfx::psCloseStroke(Object args[]) {
  856.   if (clip != clipNone)
  857.     psOut->writePS("gsave\n");
  858.   psOut->writePS("s\n");
  859.   if (clip != clipNone)
  860.     psDoClip(gTrue);
  861. }
  862.  
  863. void Gfx::opFill(Object args[]) {
  864.   cover("Gfx::opFill");
  865.   if (!state->isPath()) {
  866.     error(0, "No path in fill");
  867.     return;
  868.   }
  869.   out->fill(state);
  870.   doEndPath();
  871. }
  872.  
  873. void Gfx::psFill(Object args[]) {
  874.   if (clip != clipNone)
  875.     psOut->writePS("gsave\n");
  876.   psOut->writePS("f\n");
  877.   if (clip != clipNone)
  878.     psDoClip(gTrue);
  879. }
  880.  
  881. void Gfx::opEOFill(Object args[]) {
  882.   cover("Gfx::opEOFill");
  883.   if (!state->isPath()) {
  884.     error(0, "No path in eofill");
  885.     return;
  886.   }
  887.   out->eoFill(state);
  888.   doEndPath();
  889. }
  890.  
  891. void Gfx::psEOFill(Object args[]) {
  892.   if (clip != clipNone)
  893.     psOut->writePS("gsave\n");
  894.   psOut->writePS("f*\n");
  895.   if (clip != clipNone)
  896.     psDoClip(gTrue);
  897. }
  898.  
  899. void Gfx::opFillStroke(Object args[]) {
  900.   cover("Gfx::opFillStroke");
  901.   if (!state->isPath()) {
  902.     error(0, "No path in fill/stroke");
  903.     return;
  904.   }
  905.   out->fill(state);
  906.   out->stroke(state);
  907.   doEndPath();
  908. }
  909.  
  910. void Gfx::psFillStroke(Object args[]) {
  911.   if (clip != clipNone)
  912.     psOut->writePS("gsave\n");
  913.   psOut->writePS("B\n");
  914.   if (clip != clipNone)
  915.     psDoClip(gTrue);
  916. }
  917.  
  918. void Gfx::opCloseFillStroke(Object args[]) {
  919.   cover("Gfx::opCloseFillStroke");
  920.   if (!state->isPath()) {
  921.     error(0, "No path in closepath/fill/stroke");
  922.     return;
  923.   }
  924.   state->closePath();
  925.   out->fill(state);
  926.   out->stroke(state);
  927.   doEndPath();
  928. }
  929.  
  930. void Gfx::psCloseFillStroke(Object args[]) {
  931.   if (clip != clipNone)
  932.     psOut->writePS("gsave\n");
  933.   psOut->writePS("b\n");
  934.   if (clip != clipNone)
  935.     psDoClip(gTrue);
  936. }
  937.  
  938. void Gfx::opEOFillStroke(Object args[]) {
  939.   cover("Gfx::opEOFillStroke");
  940.   if (!state->isPath()) {
  941.     error(0, "No path in eofill/stroke");
  942.     return;
  943.   }
  944.   out->eoFill(state);
  945.   out->stroke(state);
  946.   doEndPath();
  947. }
  948.  
  949. void Gfx::psEOFillStroke(Object args[]) {
  950.   if (clip != clipNone)
  951.     psOut->writePS("gsave\n");
  952.   psOut->writePS("B*\n");
  953.   if (clip != clipNone)
  954.     psDoClip(gTrue);
  955. }
  956.  
  957. void Gfx::opCloseEOFillStroke(Object args[]) {
  958.   cover("Gfx::opCloseEOFillStroke");
  959.   if (!state->isPath()) {
  960.     error(0, "No path in closepath/eofill/stroke");
  961.     return;
  962.   }
  963.   state->closePath();
  964.   out->eoFill(state);
  965.   out->stroke(state);
  966.   doEndPath();
  967. }
  968.  
  969. void Gfx::psCloseEOFillStroke(Object args[]) {
  970.   if (clip != clipNone)
  971.     psOut->writePS("gsave\n");
  972.   psOut->writePS("b*\n");
  973.   if (clip != clipNone)
  974.     psDoClip(gTrue);
  975. }
  976.  
  977. void Gfx::doEndPath() {
  978.   if (clip == clipNormal)
  979.     out->clip(state);
  980.   else if (clip == clipEO)
  981.     out->eoClip(state);
  982.   clip = clipNone;
  983.   state->clearPath();
  984. }
  985.  
  986. void Gfx::psDoClip(GBool needRestore) {
  987.   if (needRestore)
  988.     psOut->writePS("grestore\n");
  989.   if (clip == clipNormal)
  990.     psOut->writePS("clip\n");
  991.   else
  992.     psOut->writePS("eoclip\n");
  993.   if (needRestore)
  994.     psOut->writePS("newpath\n");
  995.   clip = clipNone;
  996. }
  997.  
  998. //------------------------------------------------------------------------
  999. // path clipping operators
  1000. //------------------------------------------------------------------------
  1001.  
  1002. void Gfx::opClip(Object args[]) {
  1003.   cover("Gfx::opClip");
  1004.   clip = clipNormal;
  1005. }
  1006.  
  1007. void Gfx::psClip(Object args[]) {
  1008.   clip = clipNormal;
  1009. }
  1010.  
  1011. void Gfx::opEOClip(Object args[]) {
  1012.   cover("Gfx::opEOClip");
  1013.   clip = clipEO;
  1014. }
  1015.  
  1016. void Gfx::psEOClip(Object args[]) {
  1017.   clip = clipEO;
  1018. }
  1019.  
  1020. //------------------------------------------------------------------------
  1021. // text object operators
  1022. //------------------------------------------------------------------------
  1023.  
  1024. void Gfx::opBeginText(Object args[]) {
  1025.   cover("Gfx::opBeginText");
  1026.   state->setTextMat(1, 0, 0, 1, 0, 0);
  1027.   state->textMoveTo(0, 0);
  1028.   fontChanged = gTrue;
  1029. }
  1030.  
  1031. void Gfx::psBeginText(Object args[]) {
  1032.   psOut->writePS("[1 0 0 1 0 0] Tm\n");
  1033.   fontChanged = gTrue;
  1034. }
  1035.  
  1036. void Gfx::opEndText(Object args[]) {
  1037.   cover("Gfx::opEndText");
  1038. }
  1039.  
  1040. void Gfx::psEndText(Object args[]) {
  1041. }
  1042.  
  1043. //------------------------------------------------------------------------
  1044. // text state operators
  1045. //------------------------------------------------------------------------
  1046.  
  1047. void Gfx::opSetCharSpacing(Object args[]) {
  1048.   cover("Gfx::opSetCharSpacing");
  1049.   state->setCharSpace(args[0].getNum());
  1050. }
  1051.  
  1052. void Gfx::psSetCharSpacing(Object args[]) {
  1053.   psOut->writePS("%g Tc\n", args[0].getNum());
  1054. }
  1055.  
  1056. void Gfx::opSetFont(Object args[]) {
  1057.   GfxFont *font;
  1058.  
  1059.   cover("Gfx::opSetFont");
  1060.   if (!fonts) {
  1061.     error(0, "setfont without font dictionary");
  1062.     return;
  1063.   }
  1064.   if (!(font = fonts->lookup(args[0].getName()))) {
  1065.     error(0, "unknown font tag '%s'", args[0].getName());
  1066.     return;
  1067.   }
  1068.   if (printCommands) {
  1069.     printf("  font: '%s' %g\n",
  1070.        font->getName() ? font->getName()->getCString() : "???",
  1071.        args[1].getNum());
  1072.   }
  1073.   state->setFont(font, args[1].getNum());
  1074.   fontChanged = gTrue;
  1075. }
  1076.  
  1077. void Gfx::psSetFont(Object args[]) {
  1078.   if (fonts)
  1079.     psGfxFont = fonts->lookup(args[0].getName());
  1080.   if (psFont)
  1081.     delete psFont;
  1082.   psFont = new GString(args[0].getName());
  1083.   psFontSize = args[1].getNum();
  1084.   fontChanged = gTrue;
  1085. }
  1086.  
  1087. void Gfx::opSetTextLeading(Object args[]) {
  1088.   cover("Gfx::opSetTextLeading");
  1089.   state->setLeading(args[0].getNum());
  1090. }
  1091.  
  1092. void Gfx::psSetTextLeading(Object args[]) {
  1093.   psOut->writePS("%g TL\n", args[0].getNum());
  1094. }
  1095.  
  1096. void Gfx::opSetTextRender(Object args[]) {
  1097.   cover("Gfx::opSetTextRender");
  1098.   state->setRender(args[0].getInt());
  1099. }
  1100.  
  1101. void Gfx::psSetTextRender(Object args[]) {
  1102.   int r;
  1103.  
  1104.   r = args[0].getInt();
  1105.   psOut->writePS("%d Tr\n", r);
  1106. }
  1107.  
  1108. void Gfx::opSetTextRise(Object args[]) {
  1109.   cover("Gfx::opSetTextRise");
  1110.   state->setRise(args[0].getNum());
  1111. }
  1112.  
  1113. void Gfx::psSetTextRise(Object args[]) {
  1114.   psOut->writePS("%g Ts\n", args[0].getNum());
  1115. }
  1116.  
  1117. void Gfx::opSetWordSpacing(Object args[]) {
  1118.   cover("Gfx::opSetWordSpacing");
  1119.   state->setWordSpace(args[0].getNum());
  1120. }
  1121.  
  1122. void Gfx::psSetWordSpacing(Object args[]) {
  1123.   psOut->writePS("%g Tw\n", args[0].getNum());
  1124. }
  1125.  
  1126. void Gfx::opSetHorizScaling(Object args[]) {
  1127.   cover("Gfx::opSetHorizScaling");
  1128.   state->setHorizScaling(args[0].getNum());
  1129. }
  1130.  
  1131. void Gfx::psSetHorizScaling(Object args[]) {
  1132.   psOut->writePS("%g Tz\n", args[0].getNum());
  1133. }
  1134.  
  1135. //------------------------------------------------------------------------
  1136. // text positioning operators
  1137. //------------------------------------------------------------------------
  1138.  
  1139. void Gfx::opTextMove(Object args[]) {
  1140.   double tx, ty;
  1141.  
  1142.   cover("Gfx::opTextMove");
  1143.   tx = state->getLineX() + args[0].getNum();
  1144.   ty = state->getLineY() + args[1].getNum();
  1145.   state->textMoveTo(tx, ty);
  1146. }
  1147.  
  1148. void Gfx::psTextMove(Object args[]) {
  1149.   psOut->writePS("%g %g Td\n", args[0].getNum(), args[1].getNum());
  1150. }
  1151.  
  1152. void Gfx::opTextMoveSet(Object args[]) {
  1153.   double tx, ty;
  1154.  
  1155.   cover("Gfx::opTextMoveSet");
  1156.   tx = state->getLineX() + args[0].getNum();
  1157.   ty = args[1].getNum();
  1158.   state->setLeading(-ty);
  1159.   ty += state->getLineY();
  1160.   state->textMoveTo(tx, ty);
  1161. }
  1162.  
  1163. void Gfx::psTextMoveSet(Object args[]) {
  1164.   psOut->writePS("%g %g TD\n", args[0].getNum(), args[1].getNum());
  1165. }
  1166.  
  1167. void Gfx::opSetTextMatrix(Object args[]) {
  1168.   cover("Gfx::opSetTextMatrix");
  1169.   state->setTextMat(args[0].getNum(), args[1].getNum(),
  1170.             args[2].getNum(), args[3].getNum(),
  1171.             args[4].getNum(), args[5].getNum());
  1172.   state->textMoveTo(0, 0);
  1173.   fontChanged = gTrue;
  1174. }
  1175.  
  1176. void Gfx::psSetTextMatrix(Object args[]) {
  1177.   psOut->writePS("[%g %g %g %g %g %g] Tm\n",
  1178.          args[0].getNum(), args[1].getNum(),
  1179.          args[2].getNum(), args[3].getNum(),
  1180.          args[4].getNum(), args[5].getNum());
  1181.   fontChanged = gTrue;
  1182. }
  1183.  
  1184. void Gfx::opTextNextLine(Object args[]) {
  1185.   double tx, ty;
  1186.  
  1187.   cover("Gfx::opTextNextLine");
  1188.   tx = state->getLineX();
  1189.   ty = state->getLineY() - state->getLeading();
  1190.   state->textMoveTo(tx, ty);
  1191. }
  1192.  
  1193. void Gfx::psTextNextLine(Object args[]) {
  1194.   psOut->writePS("T*\n");
  1195. }
  1196.  
  1197. //------------------------------------------------------------------------
  1198. // text string operators
  1199. //------------------------------------------------------------------------
  1200.  
  1201. void Gfx::opShowText(Object args[]) {
  1202.   cover("Gfx::opShowText");
  1203.   if (!state->getFont()) {
  1204.     error(0, "No font in show");
  1205.     return;
  1206.   }
  1207.   doShowText(args[0].getString());
  1208. }
  1209.  
  1210. void Gfx::psShowText(Object args[]) {
  1211.   if (fontChanged) {
  1212.     psOut->writePS("/%s %g Tf\n", psFont->getCString(), psFontSize);
  1213.     fontChanged = gFalse;
  1214.   }
  1215.   psOut->writePSString(args[0].getString());
  1216.   psOut->writePS(" %g Tj\n", psGfxFont->getWidth(args[0].getString()));
  1217. }
  1218.  
  1219. void Gfx::opMoveShowText(Object args[]) {
  1220.   double tx, ty;
  1221.  
  1222.   cover("Gfx::opMoveShowText");
  1223.   if (!state->getFont()) {
  1224.     error(0, "No font in move/show");
  1225.     return;
  1226.   }
  1227.   tx = state->getLineX();
  1228.   ty = state->getLineY() - state->getLeading();
  1229.   state->textMoveTo(tx, ty);
  1230.   doShowText(args[0].getString());
  1231. }
  1232.  
  1233. void Gfx::psMoveShowText(Object args[]) {
  1234.   if (fontChanged) {
  1235.     psOut->writePS("/%s %g Tf\n", psFont->getCString(), psFontSize);
  1236.     fontChanged = gFalse;
  1237.   }
  1238.   psOut->writePS("T* ");
  1239.   psOut->writePSString(args[0].getString());
  1240.   psOut->writePS(" %g Tj\n", psGfxFont->getWidth(args[0].getString()));
  1241. }
  1242.  
  1243. void Gfx::opMoveSetShowText(Object args[]) {
  1244.   double tx, ty;
  1245.  
  1246.   cover("Gfx::opMoveSetShowText");
  1247.   if (!state->getFont()) {
  1248.     error(0, "No font in move/set/show");
  1249.     return;
  1250.   }
  1251.   state->setWordSpace(args[0].getNum());
  1252.   state->setCharSpace(args[1].getNum());
  1253.   tx = state->getLineX();
  1254.   ty = state->getLineY() - state->getLeading();
  1255.   state->textMoveTo(tx, ty);
  1256.   doShowText(args[2].getString());
  1257. }
  1258.  
  1259. void Gfx::psMoveSetShowText(Object args[]) {
  1260.   if (fontChanged) {
  1261.     psOut->writePS("/%s %g Tf\n", psFont->getCString(), psFontSize);
  1262.     fontChanged = gFalse;
  1263.   }
  1264.   psOut->writePS("%g Tw %g Tc T* ", args[0].getNum(), args[1].getNum());
  1265.   psOut->writePSString(args[2].getString());
  1266.   psOut->writePS(" %g Tj\n", psGfxFont->getWidth(args[2].getString()));
  1267. }
  1268.  
  1269. void Gfx::opShowSpaceText(Object args[]) {
  1270.   Array *a;
  1271.   Object obj;
  1272.   int i;
  1273.  
  1274.   cover("Gfx::opShowSpaceText");
  1275.   if (!state->getFont()) {
  1276.     error(0, "No font in show/space");
  1277.     return;
  1278.   }
  1279.   a = args[0].getArray();
  1280.   for (i = 0; i < a->getLength(); ++i) {
  1281.     a->get(i, &obj);
  1282.     if (obj.isNum())
  1283.       state->textShift(-obj.getNum() * 0.001 * state->getFontSize());
  1284.     else if (obj.isString())
  1285.       doShowText(obj.getString());
  1286.     else
  1287.       error(0, "Element of show/space array must be number or string");
  1288.     obj.free();
  1289.   }
  1290. }
  1291.  
  1292. void Gfx::psShowSpaceText(Object args[]) {
  1293.   Array *a;
  1294.   Object obj;
  1295.   int i;
  1296.  
  1297.   if (fontChanged) {
  1298.     psOut->writePS("/%s %g Tf\n", psFont->getCString(), psFontSize);
  1299.     fontChanged = gFalse;
  1300.   }
  1301.   a = args[0].getArray();
  1302.   for (i = 0; i < a->getLength(); ++i) {
  1303.     a->get(i, &obj);
  1304.     if (obj.isNum()) {
  1305.       psOut->writePS("%g TJm\n", obj.getNum());
  1306.     } else if (obj.isString()) {
  1307.       psOut->writePSString(obj.getString());
  1308.       psOut->writePS(" %g Tj\n", psGfxFont->getWidth(obj.getString()));
  1309.     }
  1310.     obj.free();
  1311.   }
  1312. }
  1313.  
  1314. void Gfx::doShowText(GString *s) {
  1315.   Guchar *p;
  1316.   int n;
  1317.   double dx, dy;
  1318.  
  1319.   if (fontChanged) {
  1320.     out->updateFont(state);
  1321.     fontChanged = gFalse;
  1322.   }
  1323.   state->textTransformDelta(0, state->getRise(), &dx, &dy);
  1324.   for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) {
  1325.     if (*p != '\r' && *p != '\n') {
  1326.       out->drawChar(state, state->getCurX() + dx, state->getCurY() + dy, *p);
  1327.       if (*p == ' ')
  1328.     state->textShift(state->getWordSpace());
  1329.     }
  1330.     state->textShift(state->getFontSize() * state->getFont()->getWidth(*p) +
  1331.              state->getCharSpace());
  1332.   }
  1333. }
  1334.  
  1335. //------------------------------------------------------------------------
  1336. // XObject operators
  1337. //------------------------------------------------------------------------
  1338.  
  1339. void Gfx::opXObject(Object args[]) {
  1340.   Object obj1, obj2;
  1341.  
  1342.   cover("Gfx::opXObject");
  1343.   if (!xObjDict) {
  1344.     error(0, "No XObject dictionary in 'Do' operator");
  1345.     return;
  1346.   }
  1347.   xObjDict->lookup(args[0].getName(), &obj1);
  1348.   if (!obj1.isStream("XObject")) {
  1349.     error(0, "XObject '%s' is unknown or wrong type", args[0].getName());
  1350.     obj1.free();
  1351.     return;
  1352.   }
  1353.   obj1.streamGetDict()->lookup("Subtype", &obj2);
  1354.   if (obj2.isName("Image"))
  1355.     doImage(obj1.getStream());
  1356.   else if (obj2.isName("Form"))
  1357.     doForm(obj1.getStream());
  1358.   else if (obj2.isName())
  1359.     error(0, "Unknown XObject subtype '%s'", obj2.getName());
  1360.   else
  1361.     error(0, "XObject subtype is missing or wrong type");
  1362.   obj2.free();
  1363.   obj1.free();
  1364. }
  1365.  
  1366. void Gfx::psXObject(Object args[]) {
  1367.   Object obj1, obj2;
  1368.  
  1369.   if (!xObjDict) {
  1370.     error(0, "No XObject dictionary in 'Do' operator");
  1371.     return;
  1372.   }
  1373.   xObjDict->lookup(args[0].getName(), &obj1);
  1374.   if (!obj1.isStream("XObject")) {
  1375.     error(0, "XObject '%s' is unknown or wrong type", args[0].getName());
  1376.     obj1.free();
  1377.     return;
  1378.   }
  1379.   obj1.streamGetDict()->lookup("Subtype", &obj2);
  1380.   if (obj2.isName("Image"))
  1381.     psDoImage(obj1.getStream());
  1382.   else if (obj2.isName("Form"))
  1383.     psDoForm(obj1.getStream());
  1384.   else if (obj2.isName())
  1385.     error(0, "Unknown XObject subtype '%s'", obj2.getName());
  1386.   else
  1387.     error(0, "XObject subtype is missing or wrong type");
  1388.   obj2.free();
  1389.   obj1.free();
  1390. }
  1391.  
  1392. void Gfx::doImage(Stream *str) {
  1393.   Dict *dict;
  1394.   Object obj1, obj2;
  1395.   int width, height;
  1396.   int bits;
  1397.   GBool mask;
  1398.   GfxColorSpace *colorSpace;
  1399.   GBool invert;
  1400.  
  1401.   cover("Gfx::doImage");
  1402.  
  1403.   // get stream dict
  1404.   dict = str->getDict();
  1405.  
  1406.   // get size
  1407.   dict->lookup("Width", &obj1);
  1408.   if (obj1.isNull()) {
  1409.     obj1.free();
  1410.     dict->lookup("W", &obj1);
  1411.   }
  1412.   if (!obj1.isInt())
  1413.     goto err2;
  1414.   width = obj1.getInt();
  1415.   obj1.free();
  1416.   dict->lookup("Height", &obj1);
  1417.   if (obj1.isNull()) {
  1418.     obj1.free();
  1419.     dict->lookup("H", &obj1);
  1420.   }
  1421.   if (!obj1.isInt())
  1422.     goto err2;
  1423.   height = obj1.getInt();
  1424.   obj1.free();
  1425.  
  1426.   // image or mask?
  1427.   dict->lookup("ImageMask", &obj1);
  1428.   if (obj1.isNull()) {
  1429.     obj1.free();
  1430.     dict->lookup("IM", &obj1);
  1431.   }
  1432.   mask = gFalse;
  1433.   if (obj1.isBool())
  1434.     mask = obj1.getBool();
  1435.   else if (!obj1.isNull())
  1436.     goto err2;
  1437.   obj1.free();
  1438.  
  1439.   // bit depth
  1440.   dict->lookup("BitsPerComponent", &obj1);
  1441.   if (obj1.isNull()) {
  1442.     obj1.free();
  1443.     dict->lookup("BPC", &obj1);
  1444.   }
  1445.   if (!obj1.isInt())
  1446.     goto err2;
  1447.   bits = obj1.getInt();
  1448.   obj1.free();
  1449.  
  1450.   // display a mask
  1451.   if (mask) {
  1452.     if (bits != 1)
  1453.       goto err1;
  1454.     invert = gFalse;
  1455.     dict->lookup("Decode", &obj1);
  1456.     if (obj1.isNull()) {
  1457.       obj1.free();
  1458.       dict->lookup("D", &obj1);
  1459.     }
  1460.     if (obj1.isArray()) {
  1461.       obj1.arrayGet(0, &obj2);
  1462.       if (obj2.isInt() && obj2.getInt() == 1)
  1463.     invert = gTrue;
  1464.       obj2.free();
  1465.     } else if (!obj1.isNull()) {
  1466.       goto err2;
  1467.     }
  1468.     obj1.free();
  1469.     out->drawImageMask(state, str, width, height, invert);
  1470.  
  1471.   } else {
  1472.     // get color space
  1473.     dict->lookup("ColorSpace", &obj1);
  1474.     if (obj1.isNull()) {
  1475.       obj1.free();
  1476.       dict->lookup("CS", &obj1);
  1477.     }
  1478.     if (!(obj1.isName() || obj1.isArray() || obj1.isNull()))
  1479.       goto err2;
  1480.     dict->lookup("Decode", &obj2);
  1481.     if (obj1.isNull()) {
  1482.       obj1.free();
  1483.       dict->lookup("D", &obj1);
  1484.     }
  1485.     if (!(obj2.isArray() || obj2.isNull()))
  1486.       goto err3;
  1487.     colorSpace = new GfxColorSpace(bits, &obj1, &obj2);
  1488.     if (!colorSpace->isOk())
  1489.       goto err4;
  1490.     obj1.free();
  1491.     obj2.free();
  1492.  
  1493.     // display an image
  1494.     out->drawImage(state, str, width, height, colorSpace);
  1495.     delete colorSpace;
  1496.   }
  1497.   
  1498.   return;
  1499.  
  1500.  err4:
  1501.   delete colorSpace;
  1502.  err3:
  1503.   obj2.free();
  1504.  err2:
  1505.   obj1.free();
  1506.  err1:
  1507.   error(0, "Bad image parameters");
  1508. }
  1509.  
  1510. void Gfx::psDoImage(Stream *str) {
  1511.   psOut->writeImage(str->getDict(), str, gFalse);
  1512. }
  1513.  
  1514. void Gfx::doForm(Stream *str) {
  1515.   cover("Gfx::doForm");
  1516.   error(0, "Unimplemented: form");
  1517. }
  1518.  
  1519. void Gfx::psDoForm(Stream *str) {
  1520.   error(0, "Unimplemented: form");
  1521. }
  1522.  
  1523. //------------------------------------------------------------------------
  1524. // in-line image operators
  1525. //------------------------------------------------------------------------
  1526.  
  1527. void Gfx::opBeginImage(Object args[]) {
  1528.   Object obj;
  1529.   Stream *str;
  1530.  
  1531.   cover("Gfx::opBeginImage");
  1532.  
  1533.   // build dict/stream
  1534.   str = buildImageStream();
  1535.  
  1536.   // display the image
  1537.   if (str) {
  1538.     doImage(str);
  1539.     delete str;
  1540.   }
  1541.  
  1542.   // get 'EI' tag
  1543.   nextObj(&obj);
  1544.   if (!obj.isCmd("EI"))
  1545.     error(0, "Expected 'EI' operator");
  1546.   obj.free();
  1547. }
  1548.  
  1549. void Gfx::psBeginImage(Object args[]) {
  1550.   Stream *str;
  1551.  
  1552.   // build dict/stream
  1553.   str = buildImageStream();
  1554.  
  1555.   // display the image
  1556.   // (writeImage() eats the 'EI' tag)
  1557.   if (str) {
  1558.     psOut->writeImage(str->getDict(), str, gTrue);
  1559.     delete str;
  1560.   }
  1561. }
  1562.  
  1563. Stream *Gfx::buildImageStream() {
  1564.   Object dict;
  1565.   Object obj;
  1566.   char *key;
  1567.   Stream *str;
  1568.  
  1569.   // inline image must be in stream
  1570.   if (!parser) {
  1571.     error(0, "Inline image in array content stream");
  1572.     return NULL;
  1573.   }
  1574.  
  1575.   // build dictionary
  1576.   dict.initDict();
  1577.   nextObj(&obj);
  1578.   while (!obj.isCmd("ID") && !obj.isEOF()) {
  1579.     if (!obj.isName()) {
  1580.       error(0, "Dictionary key must be a name object");
  1581.       obj.free();
  1582.       nextObj(&obj);
  1583.     } else {
  1584.       key = copyString(obj.getName());
  1585.       obj.free();
  1586.       nextObj(&obj);
  1587.       if (obj.isEOF() || obj.isError())
  1588.     break;
  1589.       dict.dictAdd(key, &obj);
  1590.     }
  1591.     nextObj(&obj);
  1592.   }
  1593.   if (obj.isEOF())
  1594.     error(0, "End of file in inline image");
  1595.   obj.free();
  1596.  
  1597.   // make stream
  1598.   str = new SubStream(parser->getStream(), &dict);
  1599.   str = str->addFilters(&dict);
  1600.  
  1601.   return str;
  1602. }
  1603.  
  1604. void Gfx::opImageData(Object args[]) {
  1605.   error(0, "Internal: got 'ID' operator");
  1606. }
  1607.  
  1608. void Gfx::psImageData(Object args[]) {
  1609.   error(0, "Internal: got 'ID' operator");
  1610. }
  1611.  
  1612. void Gfx::opEndImage(Object args[]) {
  1613.   error(0, "Internal: got 'EI'operator");
  1614. }
  1615.  
  1616. void Gfx::psEndImage(Object args[]) {
  1617.   error(0, "Internal: got 'EI'operator");
  1618. }
  1619.  
  1620. //------------------------------------------------------------------------
  1621. // type 3 font operators
  1622. //------------------------------------------------------------------------
  1623.  
  1624. void Gfx::opSetCharWidth(Object args[]) {
  1625.   cover("Gfx::opSetCharWidth");
  1626.   error(0, "Encountered 'd0' operator in content stream");
  1627. }
  1628.  
  1629. void Gfx::psSetCharWidth(Object args[]) {
  1630. }
  1631.  
  1632. void Gfx::opSetCacheDevice(Object args[]) {
  1633.   cover("Gfx::opSetCacheDevice");
  1634.   error(0, "Encountered 'd1' operator in content stream");
  1635. }
  1636.  
  1637. void Gfx::psSetCacheDevice(Object args[]) {
  1638. }
  1639.